/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.client.core.view.analysis.grr;

import com.google.common.collect.Lists;
import com.intelligent.ispc.client.core.controller.GrrController;
import com.intelligent.ispc.client.core.modal.grr.ChoiceItemDto;
import com.intelligent.ispc.client.core.modal.grr.ExportChoiceItemTableModel;
import com.intelligent.ispc.client.core.modal.grr.ItemShowRangeModel;
import com.intelligent.ispc.client.core.modal.spc.TestItemSimpleModel;
import com.intelligent.ispc.client.ex.CheckBoxHeadRenderer;
import com.intelligent.ispc.client.ex.JTextFieldEx;
import com.intelligent.ispc.client.utils.ArrayUtils;
import com.intelligent.ispc.client.utils.GBC;
import com.intelligent.ispc.client.utils.UIConstant;
import com.intelligent.ispc.client.utils.WindowUtils;
import com.intelligent.ispc.common.utils.StringUtils;
import com.intelligent.ispc.core.dto.GrrGroupDto;
import com.intelligent.ispc.core.dto.GrrParamDto;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by cherry on 2016/8/24.
 */

@org.springframework.stereotype.Component
public class ExportChoiceItemDialog extends JDialog {

    @Autowired
    private GrrController grrController;

    private ExportChoiceItemTableModel choiceItemTableModel;
    private ItemShowRangeModel rangeModel;
    private GrrParamDto grrParamDto;
    private GrrGroupDto grrGroupDto;

    private List<String> itemNames;
    private List<RowFilter<Object, Object>> scopeList;
    private int stepSize = 0;
    private int colIndex;
    private String exportType;
    private final Dimension dialogSize = new Dimension(400, 500);

    /**
     * ExportChoiceItemDialog constructor
     */
    public ExportChoiceItemDialog() {
        this.setTitle("GRR Test Item");
        WindowUtils.centerWindowOnScreen(this);
        this.setPreferredSize(dialogSize);
        this.pack();
        this.setModal(true);
    }

    @PostConstruct
    private void initComponent() {
        this.setLayout(new GridBagLayout());
        tablePanel = new JPanel(new GridBagLayout());
        testItemTable = new JTable();
        String[] columns = UIConstant.ANALYSIS_GRR_CHOICEITEM_ITEMTITLE;
        choiceItemTableModel = new ExportChoiceItemTableModel(columns);

        JPanel radioPanel = new JPanel(new GridBagLayout());
        allRadio = new JRadioButton("All");
        selectedRadio = new JRadioButton("Selected");
        unSelectedRadio = new JRadioButton("UnSelected");
        selectAllCb = new JCheckBox();
        radioPanel.add(allRadio, new GBC(0, 0).setFill(GBC.HORIZONTAL).setInsets(0, 10, 0, 10));
        radioPanel.add(selectedRadio, new GBC(1, 0).setFill(GBC.HORIZONTAL).setInsets(0, 0, 0, 10));
        radioPanel.add(unSelectedRadio, new GBC(2, 0).setFill(GBC.HORIZONTAL).setInsets(0, 0, 0, 10));
        radioPanel.add(selectAllCb, new GBC(3, 0).setFill(GBC.HORIZONTAL).setInsets(0, 0, 0, 5));
        radioPanel.add(new JLabel("Select All"), new GBC(4, 0).setFill(GBC.HORIZONTAL).setInsets(0, 0, 0, 10));
        radioPanel.add(new JPanel(), new GBC(5, 0).setFill(GBC.HORIZONTAL).setWeight(100, 0));
        ButtonGroup group = new ButtonGroup();
        group.add(allRadio);
        group.add(selectedRadio);
        group.add(unSelectedRadio);
        allRadio.setSelected(true);

        colIndex = 0;
        this.add(radioPanel, new GBC(0, colIndex).setFill(GBC.HORIZONTAL).setWeight(100, 0).setInsets(10, 0, 5, 0));
        colIndex++;
        filterText = new JTextFieldEx();
        filterText.setPlaceHolder("Filter");
        this.add(filterText, new GBC(0, colIndex).setFill(GBC.BOTH));
        colIndex++;

        JPanel btnPanel = new JPanel(new GridBagLayout());
        JPanel pagePanel = new JPanel(new GridBagLayout());
        selectedCountLable = new JLabel();
        submitBtn = new JButton("Submit");
        cancelBtn = new JButton("Cancel");
        showCountJcb = new JComboBox();

        String[] stepValues = UIConstant.ANALYSIS_GRR_CHOICEITEM_STEPVALUES;
        showStepJcb = new JComboBox(stepValues);
        final Dimension comboBoxSize = new Dimension(150, 25);
        showCountJcb.setPreferredSize(comboBoxSize);
        rangeModel = new ItemShowRangeModel();
        showCountJcb.setModel(rangeModel);

        pagePanel.add(new JLabel("Step Count : "), new GBC(0, 0).setFill(GBC.BOTH).setInsets(10, 5, 5, 5));
        pagePanel.add(showStepJcb, new GBC(1, 0).setFill(GBC.BOTH).setInsets(10, 0, 5, 5));
        pagePanel.add(new JLabel(), new GBC(2, 0).setFill(GBC.BOTH).setWeight(100, 100));
        pagePanel.add(new JLabel("Value Range"), new GBC(3, 0).setFill(GBC.BOTH).setInsets(10, 0, 5, 0));
        pagePanel.add(showCountJcb, new GBC(4, 0).setFill(GBC.BOTH).setInsets(10, 0, 5, 0));
        btnPanel.add(selectedCountLable, new GBC(0, 1).setFill(GBC.HORIZONTAL).setWeight(100, 100).setInsets(0, 5, 0, 0));
        btnPanel.add(submitBtn, new GBC(1, 1).setFill(GBC.HORIZONTAL).setInsets(10, 0, 5, 0));
        btnPanel.add(cancelBtn, new GBC(2, 1).setFill(GBC.HORIZONTAL).setInsets(10, 5, 5, 5));

        /* table init start */
        scrollPane = new JScrollPane();
        scrollPane.setEnabled(false);
        final Dimension scrollPaneSize = new Dimension(180, 160);
        scrollPane.setPreferredSize(scrollPaneSize);
        testItemTable.getTableHeader().setReorderingAllowed(false);
        DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();
        tcr.setHorizontalAlignment(SwingConstants.CENTER);
        testItemTable.setDefaultRenderer(Object.class, tcr);
        testItemTable.setModel(choiceItemTableModel);
        choiceItemSorter = new TableRowSorter(choiceItemTableModel);
        testItemTable.setRowSorter(choiceItemSorter);
        testItemTable.getTableHeader().setDefaultRenderer(new CheckBoxHeadRenderer(testItemTable, false));

        testItemTable.getColumnModel().getColumn(0).setPreferredWidth(10);
        testItemTable.getColumnModel().getColumn(0).setMaxWidth(50);
        testItemTable.getColumnModel().getColumn(0).setMinWidth(30);

        testItemTable.getColumnModel().getColumn(1).setPreferredWidth(20);
        testItemTable.getColumnModel().getColumn(1).setMaxWidth(50);
        testItemTable.getColumnModel().getColumn(1).setMinWidth(30);

        JCheckBox checkBox = new JCheckBox();
        TableColumnModel tcm = testItemTable.getColumnModel();
        tcm.getColumn(0).setCellEditor(new DefaultCellEditor(checkBox));
        testItemTable.getTableHeader().setVisible(true);

        scrollPane.setViewportView(testItemTable);
        tablePanel.add(scrollPane, new GBC(0, 0).setFill(GBC.BOTH).setWeight(100, 100));
        /* table init end */

        this.add(tablePanel, new GBC(0, colIndex).setFill(GBC.BOTH).setWeight(100, 100));
        colIndex++;
        this.add(pagePanel, new GBC(0, colIndex).setFill(GBC.HORIZONTAL).setInsets(0));
        colIndex++;
        this.add(btnPanel, new GBC(0, colIndex).setFill(GBC.HORIZONTAL).setInsets(0));

        scopeList = new ArrayList<RowFilter<Object, Object>>();
        scopeList.add(RowFilter.regexFilter("", 0));
        scopeList.add(RowFilter.regexFilter("", 2));
        scopeList.add(RowFilter.numberFilter(RowFilter.ComparisonType.AFTER, 0, 1));
        scopeList.add(RowFilter.numberFilter(RowFilter.ComparisonType.BEFORE, stepSize + 1, 1));

        registerEvent();
    }

    /**
     * show export dialog
     *
     * @param fileName    current selected file for fileName
     * @param filePath    current selected file for filePath
     * @param grrGroupDto current selected group object
     * @param type        current selected export type
     */
    public void showDialog(String fileName, String filePath, GrrGroupDto grrGroupDto, String type) {
        grrParamDto = new GrrParamDto();
        grrParamDto.setGrrName(fileName);
        grrParamDto.setFilePath(filePath);
        this.grrGroupDto = grrGroupDto;
        this.exportType = type;
        selectAllCb.setSelected(false);
        showStepJcb.setSelectedIndex(UIConstant.INIT_SELECT_STEP);
        setRangeData();
        choiceItemTableModel.setCacheViewIndex(getCheckViewIndex());
        allRadio.setSelected(true);
        radioActionPerformed("All");
        filterText.setText("");
        fireFilter();
        setSelectAllCb();
        JScrollBar jsVB = scrollPane.getVerticalScrollBar();
        if (jsVB != null) {
            jsVB.setValue(0);
        }
        selectedCountLable.setText("Selected Count: " + choiceItemTableModel.getSelectedCount());
        this.setSize(dialogSize);
        this.setVisible(true);
    }

    /**
     * set export model data source
     *
     * @param dtos searched export data source
     */
    public void setTableData(List<ChoiceItemDto> dtos) {
        List<ChoiceItemDto> choiceItemDtos = Lists.newArrayList();
        try {
            choiceItemDtos = ArrayUtils.deepCopy(dtos);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        choiceItemTableModel.setData(choiceItemDtos);
        choiceItemTableModel.setViewData(getTableViewData());
        selectedCountLable.setText("Selected Count: " + choiceItemTableModel.getSelectedCount());
    }

    private void setRangeData() {
        String stepSelectedValue = showStepJcb.getSelectedItem().toString();
        stepSize = StringUtils.isBlank(stepSelectedValue) ? choiceItemTableModel.getData().size() : Integer.parseInt(stepSelectedValue);
        List<String> values = Lists.newArrayList();
        int startIndex = 0;
        for (int i = 0; i < choiceItemTableModel.getData().size(); i++) {
            if (i == 0) {
                values.add("");

            } else if (i % stepSize == 0) {
                String rangeData = startIndex + 1 + "~" + i;
                startIndex = i;
                values.add(rangeData);
            }
        }

        if (choiceItemTableModel.getData().size() == stepSize) {
            String rangeData = startIndex + 1 + "~" + choiceItemTableModel.getData().size();
            values.add(rangeData);
        } else {
            if (startIndex != choiceItemTableModel.getData().size()) {
                String rangeData = startIndex + 1 + "~" + choiceItemTableModel.getData().size();
                values.add(rangeData);
            }
        }

        rangeModel.setData(values);
    }

    private void fireFilter() {
        RowFilter textFilter = RowFilter.regexFilter(filterText.getText(), 2);
        scopeList.set(1, textFilter);
        choiceItemSorter.setRowFilter(RowFilter.andFilter(scopeList));
        testItemTable.repaint();
        choiceItemTableModel.setViewData(getTableViewData());
    }

    private void itemCheckBoxClicked(MouseEvent e) {
        if (e.getClickCount() == 1) {
            int col = testItemTable.columnAtPoint(e.getPoint());
            int row = testItemTable.rowAtPoint(e.getPoint());
            int rowIndex = ((JTable) e.getSource()).convertRowIndexToModel(row);
            int columnIndex = ((JTable) e.getSource()).convertColumnIndexToModel(col);

            if (columnIndex == 0) {
                Object value = testItemTable.getValueAt(row, 0);
                if (value == null) {
                    choiceItemTableModel.setValueAt(false, rowIndex, 0);
                } else if (Boolean.valueOf(value.toString())) {
                    choiceItemTableModel.setValueAt(false, rowIndex, columnIndex);
                } else {
                    choiceItemTableModel.setValueAt(true, rowIndex, columnIndex);
                }
            }

            selectedCountLable.setText("Selected Count: " + choiceItemTableModel.getSelectedCount());
            setSelectAllCb();
            testItemTable.repaint();
        }
    }

    private void radioActionPerformed(String type) {
        if ("SELECT".equals(type)) {
            scopeList.set(0, RowFilter.regexFilter("true", 0));
        } else if ("UNSELECT".equals(type)) {
            scopeList.set(0, RowFilter.regexFilter("false", 0));
        } else {
            scopeList.set(0, RowFilter.regexFilter("", 0));
        }

        choiceItemSorter.setRowFilter(RowFilter.andFilter(scopeList));
        testItemTable.repaint();
        choiceItemTableModel.setViewData(getTableViewData());
    }

    private void registerEvent() {

        allRadio.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                radioActionPerformed("ALL");
                Thread.currentThread().interrupt();
            }
        });

        selectedRadio.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                radioActionPerformed("SELECT");
                Thread.currentThread().interrupt();
            }
        });

        unSelectedRadio.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                radioActionPerformed("UNSELECT");
                Thread.currentThread().interrupt();
            }
        });

        cancelBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                resetTableCheck();
                ExportChoiceItemDialog.this.dispose();
                Thread.currentThread().interrupt();
            }
        });

        filterText.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                fireFilter();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                fireFilter();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                fireFilter();
            }
        });

        testItemTable.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                itemCheckBoxClicked(e);
                Thread.currentThread().interrupt();
            }
        });

        choiceItemTableModel.onCheckChange(new TestItemSimpleModel.CheckChangeEvent() {
            @Override
            public void change() {
                selectedCountLable.setText("Selected Count: " + choiceItemTableModel.getSelectedCount());
            }
        });

        showCountJcb.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    JScrollBar jsVB = scrollPane.getVerticalScrollBar();
                    if (jsVB != null) {
                        jsVB.setValue(0);
                    }
                    searchItem();
                }
            }
        });

        showStepJcb.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    setRangeData();
                }
            }
        });

//        selectAllCb.addItemListener(new ItemListener() {
//            @Override
//            public void itemStateChanged(ItemEvent e) {
//                choiceItemTableModel.selectAllData(selectAllCb.isSelected());
//                selectedCountLable.setText("Selected Count: " + choiceItemTableModel.getSelectedCount());
//                setSelectAllCb();
//            }
//        });
        selectAllCb.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                choiceItemTableModel.selectAllData(selectAllCb.isSelected());
                selectedCountLable.setText("Selected Count: " + choiceItemTableModel.getSelectedCount());
                setSelectAllCb();
            }
        });

        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                resetTableCheck();
                Thread.currentThread().interrupt();
            }
        });
    }

    private void searchItem() {
        String selectData = showCountJcb.getSelectedItem().toString();
        if (!StringUtils.isBlank(selectData)) {
            String[] range = selectData.split("~");
            int endData = Integer.parseInt(range[1]);
            int startData = Integer.parseInt(range[0]);
            scopeList.set(2, RowFilter.numberFilter(RowFilter.ComparisonType.AFTER, startData - 1, 1));
            scopeList.set(3, RowFilter.numberFilter(RowFilter.ComparisonType.BEFORE, endData + 1, 1));
        } else {
            scopeList.set(2, RowFilter.numberFilter(RowFilter.ComparisonType.AFTER, 0, 1));
            scopeList.set(3, RowFilter.numberFilter(RowFilter.ComparisonType.BEFORE, choiceItemTableModel.getData().size(), 1));
            showStepJcb.setSelectedIndex(0);
        }

        choiceItemSorter.setRowFilter(RowFilter.andFilter(scopeList));
        testItemTable.repaint();
        setSelectAllCb();
        choiceItemTableModel.setViewData(getTableViewData());
    }

    private void setSelectAllCb() {
        CheckBoxHeadRenderer render = (CheckBoxHeadRenderer) testItemTable.getTableHeader().getDefaultRenderer();
        boolean flag = render.isSelected();

        int startIndex = 0;
        int endIndex = 0;
        int checkCount = 0;
        int unCheckCount = 0;

        String rangeValue = showCountJcb.getSelectedItem().toString();
        if (StringUtils.isBlank(rangeValue)) {
            endIndex = choiceItemTableModel.getData().size();
            for (ChoiceItemDto dto : choiceItemTableModel.getData()) {
                if (dto.getViewCheck()) {
                    checkCount++;
                } else {
                    unCheckCount++;
                }
            }

        } else {
            startIndex = Integer.parseInt(rangeValue.split("~")[0]) - 1;
            endIndex = Integer.parseInt(rangeValue.split("~")[1]);

            if (choiceItemTableModel.getData() == null) {
                return;
            }

            int count = choiceItemTableModel.getData().size();
            if (count < endIndex) {
                endIndex = count;
            }

            for (int i = startIndex; i < endIndex; i++) {
                ChoiceItemDto dto = choiceItemTableModel.getData().get(i);
                if (dto.getViewCheck()) {
                    checkCount++;
                } else {
                    unCheckCount++;
                }
            }
        }

        int value = endIndex - startIndex;
        if (checkCount == value) {
            render.setCheckAll(true);
            if (value == choiceItemTableModel.getData().size()) {
                selectAllCb.setSelected(true);
            }
        } else {
            if (flag) {
                render.setCheckAll(false);
            }
            selectAllCb.setSelected(false);
        }

        if (unCheckCount == value) {
            render.setCheckAll(false);
            if (value == choiceItemTableModel.getData().size()) {
                selectAllCb.setSelected(false);
            }
        }
    }

    /**
     * @return check selected item count is valid or not
     */
    public boolean checkItemCount() {
        boolean flag = false;
        List<ChoiceItemDto> valueDtos = choiceItemTableModel.getData();
        for (ChoiceItemDto keyValueDto : valueDtos) {
            if (("true").equals(keyValueDto.getViewCheck().toString())) {
                flag = true;
                break;
            }
        }
        return flag;
    }

    /**
     * @return table view data
     */
    public int[] getTableViewData() {
        int[] items = new int[testItemTable.getRowCount()];
        for (int i = 0; i < testItemTable.getRowCount(); i++) {
            items[i] = testItemTable.convertRowIndexToModel(i);
        }
        return items;
    }

    private List<Integer> getCheckViewIndex() {
        List<Integer> flagIndexs = Lists.newArrayList();
        int count = choiceItemTableModel.getData().size();
        for (int i = 0; i < count; i++) {
            ChoiceItemDto dto = choiceItemTableModel.getData().get(i);
            if (dto.getViewCheck()) {
                flagIndexs.add(i);
            }
        }
        return flagIndexs;

    }

    /**
     * @return get selected list item names
     */
    public List<String> getItemNames() {
        itemNames = Lists.newArrayList();
        for (ChoiceItemDto dto : choiceItemTableModel.getData()) {
            if (dto.getViewCheck()) {
                itemNames.add(dto.getItemName());
            }
        }
        return itemNames;
    }

    /**
     * set check viewData index cache
     */
    public void setCacheData() {
        choiceItemTableModel.setCacheViewIndex(getCheckViewIndex());
    }

    private void resetTableCheck() {
        int size = choiceItemTableModel.getData().size();
        for (int i = 0; i < size; i++) {
            choiceItemTableModel.getData().get(i).setViewCheck(false);
            int rowFlagCount = choiceItemTableModel.getCacheViewIndex().size();

            for (int j = 0; j < rowFlagCount; j++) {

                if (i == j) {
                    choiceItemTableModel.getData().get(i).setViewCheck(true);
                }
            }
        }
    }

    public String getExportType() {
        return exportType;
    }

    public JButton getSubmitBtn() {
        return submitBtn;
    }

    private JTable testItemTable;
    private JTextFieldEx filterText;
    private JScrollPane scrollPane;
    private JPanel tablePanel;

    private TableRowSorter choiceItemSorter;

    private JRadioButton allRadio;
    private JRadioButton selectedRadio;
    private JRadioButton unSelectedRadio;
    private JCheckBox selectAllCb;
    private JButton submitBtn;
    private JButton cancelBtn;
    private JLabel selectedCountLable;
    private JComboBox showCountJcb;
    private JComboBox showStepJcb;
}
